package b.acct.impl

import akka.{Done, NotUsed}
import b.acct.api.{CC开户Request, CC账户, CC转账Request, T账户Service}
import b.cif.api.T客户Service
import b.utils.api.T底层Service
import b.utils.entity._
import com.lightbend.lagom.scaladsl.api.ServiceCall
import com.lightbend.lagom.scaladsl.api.transport.NotFound
import com.lightbend.lagom.scaladsl.persistence.cassandra.CassandraSession
import com.lightbend.lagom.scaladsl.persistence.{PersistentEntityRef, PersistentEntityRegistry, ReadSide}

import scala.concurrent.{ExecutionContext, Future}


class C账户ServiceImpl(
                      registry: PersistentEntityRegistry,
                      readSide: ReadSide,
                      db: CassandraSession,
                      cif: T客户Service,
                      base: T底层Service)(implicit ex: ExecutionContext) extends T账户Service with T事务ServiceImpl {

  val v集群号 = 1
  assert(v集群号 < 10)
  val v机器号 = 1
  assert(v机器号 < 100)
  val v流水号产生器 = new C流水号产生器(v机器号, v集群号)

  override def f开户(): ServiceCall[CC开户Request, String] = ServiceCall { rq =>
    val v序号 = cif.f取账户序号(rq.v客户号).invoke()
    v序号.flatMap { x序号 =>
      val v账号 = rq.v客户号 + "%06d".format(x序号)
      refFor(v账号).ask(CC开户Command(v账号)).map(_ => v账号)
    }
  }
  override def f账户查询(v账号: String): ServiceCall[NotUsed, CC账户] = ServiceCall { req =>
    refFor(v账号).ask(CC账户GetCommand())
      .map(_.getOrElse(throw NotFound(s"账户[$v账号]")))
  }
  abstract class AC转账参与方(v账号: String) extends T事务参与方[T账户Command] {
    val entity: PersistentEntityRef[T账户Command] = refFor(v账号)
    def f确认: Future[Done] = entity.ask(CC改余额ConfirmCommand(v事务ID))
    def f取消: Future[Done] = entity.ask(CC改余额CancelCommand(v事务ID))
  }
  case class CC转账转出方(v事务ID: Long, v请求: CC转账Request)
    extends AC转账参与方(v请求.v转出账号) {
    def f尝试: Future[Done] = entity.ask(CC转出TryCommand(v事务ID, v请求))
  }
  case class CC转账转入方(v事务ID: Long, v请求: CC转账Request)
    extends AC转账参与方(v请求.v转入账号) {
    def f尝试: Future[Done] = entity.ask(CC转入TryCommand(v事务ID, v请求))
  }
  override def f转账(): ServiceCall[CC转账Request, String] = ServiceCall { req =>
    val v事务ID: Long = v流水号产生器.nextId()
    val v参与方s = Map(
        "OUT" -> CC转账转出方(v事务ID, req),
        "IN" -> CC转账转入方(v事务ID, req)
    )
    fTCC(registry, v事务ID, "转账", v参与方s) map { _ => v事务ID.toString }
  }
  private[this] def refFor(v账号: String): PersistentEntityRef[T账户Command] =
    registry.refFor[C账户PersistentEntity](s"/$v账号")
}
